using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DataService.Helper;
using DataService.Helper.Kafka;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Opc.Ua.Sample.Service;
using OpcuaClient.Model;

namespace OpcuaClient.Service
{
    public class ConstructService
    {
        LogHelper LogHelper = new LogHelper("OpcuaClient");
        public OpcConnectService OpcConnectService { get; set; }
        private Construction Construction { get; set; }

        private List<CollectReadService> CollectionServiceList { get; set; }
        List<string> Keys { get; set; }
        public List<Collection> Collections { get; set; }

        private KafkaProducer Producer { get; set; }

        private static event EventHandler m_SendedMessage;
        /// <summary>
        /// Raised after a node is selected in the control.
        /// </summary>
        public event EventHandler AfterSendMessage { add { m_SendedMessage += value; } remove { m_SendedMessage -= value; } }
        public ConstructService() { }

        public ConstructService(OpcConnectService service, Construction construction, List<CollectReadService> collectionServices)
        {
            Construction = construction;
            OpcConnectService = service;
            CollectionServiceList = collectionServices;

            Producer = new KafkaProducer();
            Keys = Construction.KeyValues.Select(m => m.Key).ToList();
            Collections = new List<Collection>();
        }

        /// <summary>
        /// 添加点位数据变更事件
        /// </summary>
        public void Start()
        {
            if (CollectionServiceList == null || CollectionServiceList.Count == 0) return;
            foreach (var item in CollectionServiceList)
            {
                item.AfterValueChanged += new EventHandler(CollectionValueChange);
            }
        }
        /// <summary>
        /// 将采集点位添加到结构体
        /// </summary>
        /// <param name="collection"></param>
        object obj = new object();
        private bool AddCollection(Collection collection)
        {
            lock (obj)
            {
                if (collection == null) return false;
                if (Collections.Count == 0)
                {
                    Collections.Add(collection);
                    return true;
                }
                var collection2 = Collections.FirstOrDefault(m => m.Key == collection.Key);
                if (collection2 == null)
                {
                    Collections.Add(collection);
                    return true;
                }
                if (collection.Value.Equals(collection2.Value))
                {
                    return false;
                }
                int idx = Collections.IndexOf(collection2);
                Collections[idx].Value = collection.Value;
                Collections[idx].CollectTime = collection.CollectTime;
                return true;
            }
        }

        /// <summary>
        /// 点位数据变更事件
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="e"></param>
        private void CollectionValueChange(object obj, EventArgs e)
        {
            if (obj == null) return;
            try
            {
                Collection collection = JsonConvert.DeserializeObject<Collection>(JsonConvert.SerializeObject(obj));
                string value = collection.Value.ToString().ToLower();
                if (value == "false" || string.IsNullOrWhiteSpace(value))
                {
                    return;
                }
                if (Keys.Contains(collection.Key))
                {
                    var keyValue = Construction.KeyValues.FirstOrDefault(m => m.Key == collection.Key);

                    if (!string.IsNullOrWhiteSpace(keyValue.Filter) && keyValue.Filter.Split(',').Contains(value)) return;

                    if (!AddCollection(collection)) return;

                    keyValue.Value = collection.Value;
                    keyValue.CollectTime = DateTime.Now;
                    keyValue.Status = true;
                    UpdateConstructionKeyValue(keyValue);

                    //UpdateCollectionToServer(collection);
                }
                //Task.Factory.StartNew(() => {
                //    UpdateCollectionStatus(collection);
                //});
            }
            catch (Exception ex)
            {
                LogHelper.Error("ConstructionService.ChangeValue:" + ex.Message + "\r\n" + ex.StackTrace);
            }
        }

        /// <summary>
        /// 保存结构体值，如果当前值为关键值测直接保存
        /// </summary>
        private void UpdateConstructionKeyValue(ConstructionKeyValue keyValue)
        {
            if (string.IsNullOrWhiteSpace(keyValue.Precondition.Trim()) || keyValue.PreFrequency == 0)
            {
                UpdateKeyValue(keyValue);
            }

            ConstructionKeyValue preKeyValue = Construction.KeyValues.FirstOrDefault(m => !string.IsNullOrWhiteSpace(m.Precondition) && m.Precondition == keyValue.Key);
            if (preKeyValue != null)
            {
                CollectPreKeyValue(preKeyValue);
            }
        }

        /// <summary>
        /// 读取前值
        /// </summary>
        /// <param name="construction"></param>
        /// <param name="keyValue"></param>
        private void CollectPreKeyValue(ConstructionKeyValue keyValue)
        {
            Thread.Sleep(keyValue.PreFrequency);
            Collection collection = Collections.FirstOrDefault(m => m.Key == keyValue.Key);
            //3次读取
            int count = 0;
            string value = collection == null ? "" : collection.Value.ToString();
            while ((collection == null || value.Equals(keyValue.Value) || !string.IsNullOrWhiteSpace(value)) && count < 3)//(!collection.Status || string.IsNullOrWhiteSpace(collection.Value.ToString())) && count < 3)
            {
                Thread.Sleep(keyValue.PreFrequency);
                collection = Collections.FirstOrDefault(m => m.Key == keyValue.Key);
                if (collection != null)
                {
                    value = collection.Value.ToString();
                }
                count++;
            }
            if (value.Equals(keyValue.Value))
            {
                keyValue.Value = "";
            }
            else
            {
                keyValue.Value = value;
            }
            keyValue.CollectTime = DateTime.Now;
            //读取结束后，采集点位值正常更新结构体
            UpdateKeyValue(keyValue);

            //如果此点位还有被引用则继续读取
            ConstructionKeyValue preKeyValue = Construction.KeyValues.FirstOrDefault(m => !string.IsNullOrWhiteSpace(m.Precondition) && m.Precondition == keyValue.Key);
            if (preKeyValue != null)
            {
                CollectPreKeyValue(preKeyValue);
            }
        }
        /// <summary>
        /// 更新CONSTRUCTION'S KEYVALUE
        /// </summary>
        /// <param name="construction"></param>
        /// <param name="collection"></param>
        private void UpdateKeyValue(ConstructionKeyValue keyValue)
        {
            var value = Construction.KeyValues.FirstOrDefault(m => m.Key == keyValue.Key);
            int idx = Construction.KeyValues.IndexOf(value);
            Construction.KeyValues[idx] = keyValue;
            Construction.CollectionTime = DateTime.Now;
            if (keyValue.IsKeyWord)
            {
                if (Construction.Frequency > 0)
                {
                    Thread.Sleep(Construction.Frequency);
                }
                SendMessage();
            }
            //UpdateConstructionToServer();
        }

        /// <summary>
        /// 更新结构体到服务器
        /// </summary>
        /// <param name="construction"></param>
        private void UpdateConstructionToServer()
        {
            Construction construction = OpcConnectService.Server.Constructions.FirstOrDefault(m => m.Key == Construction.Key);
            int idx = OpcConnectService.Server.Constructions.IndexOf(construction);
            OpcConnectService.Server.Constructions[idx] = construction;
        }

        /// <summary>
        /// 将结构体发送到消息队列（TOPIC）
        /// </summary>
        /// <param name="keyValues"></param>
        private void SendMessage()
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var item in Construction.KeyValues)
            {
                string key = string.IsNullOrWhiteSpace(item.Code) ? item.Key : item.Code;
                stringBuilder.Append($"\"{key}\":\"{item.Value}\",");
            }
            long timeStamp = (long)(DateTime.Now - DateTime.Parse("1970-1-1")).TotalMilliseconds;
            string value = "{" + stringBuilder.ToString() + $"\"CollectTime\":{timeStamp}" + "}";
            Producer.Produce(OpcConnectService.Server.MessageUrl, Construction.Topic, value);
        }

        public void Stop()
        {
            foreach (var item in CollectionServiceList)
            {
                item.AfterValueChanged -= new EventHandler(CollectionValueChange);
            }
        }
    }
}
